﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Windows.Forms;

namespace Tb
{
    public partial class Form1 : Form
    {
        private string remoteIP;
        private int remotePort;
        private string proxyIP;
        private int proxyPort;
        private NetworkStream tcpServer = null;
        
        public Form1()
        {
            InitializeComponent();
            LogWritting();
            GetPreData();
            if (Environment.GetCommandLineArgs().Contains("Test"))
            {
                textBox1.Text = "127.0.0.1";
                textBox3.Text = "115.29.184.254";
                textBox4.Text = "80";
            }
        }

        private void GetPreData()
        {
            if (File.Exists("cfg.dat"))
            {
                var lines = File.ReadAllLines("cfg.dat", Encoding.UTF8);
                if (lines.Length>=4)
                {
                    textBox1.Text = lines[0];
                    textBox2.Text = lines[1];
                    textBox3.Text = lines[2];
                    textBox4.Text = lines[3];
                }
            }
        }
        private void SetPreData()
        {
            if (File.Exists("cfg.dat"))
            {
               File.Delete("cfg.dat");
            }
           
            File.WriteAllLines("cfg.dat", new[]
            {
                textBox1.Text,
                textBox2.Text,
                textBox3.Text,
                textBox4.Text
            },Encoding.UTF8);
        }

        private void button1_Click(object sender, EventArgs e)
        {
            remoteIP = textBox1.Text;
            remotePort = int.Parse(textBox2.Text);

            proxyIP =checkBox1.Checked?"127.0.0.1": textBox3.Text;
            proxyPort = int.Parse(textBox4.Text);
            this.panel1.Enabled = false;
            ThreadPool.QueueUserWorkItem(Start);
            SetPreData();
            if (checkBox1.Checked)
            {
                ThreadPool.QueueUserWorkItem(TestListner);
            }
        }


        void Start(object obj)
        {
            TcpClient tc = null;
            while (true)
            {
                try
                {
                    tc = new TcpClient
                    {
                        SendTimeout = 300000,
                        ReceiveTimeout = 300000
                    };
                    tc.Connect(remoteIP, remotePort);
                    tcpServer = tc.GetStream();
                    var bt = Encoding.UTF8.GetBytes("ok"); //这里发送一个连接提示
                    tcpServer.Write(bt, 0, bt.Length);
                    Log("连接成功");
                    Jieshou();
                }
                catch (Exception ex)
                {
                    Log("连接失败，原因：" + ex);
                    tc.Close();
                    Thread.Sleep(5000);
                }
            }
           
        }

        private void Jieshou()
        {
            // var dataflag = BitConverter.GetBytes(1000000000 - 1);
            var beat = new byte[] { 66, 69, 65, 84, 33, 33 };
            while (true)
            {
                var bt = new byte[6];
                var len= tcpServer.Read(bt, 0, bt.Length);
                if (bt.SequenceEqual(beat))
                {
                    Console.WriteLine($"TM:{DateTime.Now} BEAT!!");
                    continue;
                }
                var tc1 = new TcpClient
                {
                    SendTimeout = 300000,
                    ReceiveTimeout = 300000
                };
                tc1.Connect(remoteIP,remotePort);
                var tc2 = new TcpClient
                {
                    SendTimeout = 300000,
                    ReceiveTimeout = 300000
                };
                tc2.Connect(proxyIP,proxyPort);



                tc1.GetStream().Write(bt, 0, len);
                var obj1 = (object)(new[] { tc1, tc2 });
                var obj2 = (object)(new[] {  tc2,tc1 });
                ThreadPool.QueueUserWorkItem(Transfer, obj1);
                ThreadPool.QueueUserWorkItem(Transfer, obj2);
            }
        }
        

        private void Transfer(object obj)
        {
            var tc1 = ((TcpClient[])obj)[0];
            var tc2 = ((TcpClient[])obj)[1];
            try
            {
                var ns1 = tc1.GetStream();
                var ns2 = tc2.GetStream();
                while (true)
                {
                    try
                    {
                        var bt = new byte[10240];
                        var count = ns1.Read(bt, 0, bt.Length);
                        if (count == 0)
                        {
                            ns1.Dispose();
                            ns2.Dispose();
                            tc1.Close();
                            tc2.Close();
                            break;
                        }

                        ns2.Write(bt, 0, count);
                        Log($"Tid:{Thread.CurrentThread.ManagedThreadId} Read From:{tc1.Client.RemoteEndPoint} SendTo:{tc2.Client.RemoteEndPoint},Len:{count}");

                    }
                    catch (Exception ex)
                    {
                        ns1.Dispose();
                        ns2.Dispose();
                        tc1.Close();
                        tc2.Close();
                        break;
                    }
                }
            }
            catch (Exception)
            {
                tc1.Close();
                tc2.Close();
            }
            
        }
        const string LogPath = "log.log";
        private readonly StringBuilder _logBuilder = new StringBuilder();
        private static int _times = 0;
        //private void Log(string msg)
        //{
        //    var action =(Action)(() =>
        //    {
        //        var content = $"{DateTime.Now}\r\n{msg}\r\n-------------------------\r\n";
        //        textBox5.AppendText(content);
        //        lock (_logBuilder)
        //        {
        //            _logBuilder.Append(content);
        //            if (Interlocked.Increment(ref _times) > 20)
        //            {
        //                File.AppendAllText(LogPath, textBox5.Text);
        //                textBox5.Clear();
        //                Interlocked.Exchange(ref _times, 0);
        //            }
        //        }
                
        //    });
        //    if (textBox5.InvokeRequired)
        //    {
        //        textBox5.Invoke(action);
        //    }
        //    else
        //    {
        //        action();
        //    }
        //}

        private  void Log(string msg)
        {
            var content = $"{DateTime.Now}\r\n {msg}\r\n-------------------------\r\n";
           
            lock (_logBuilder)
            {
                if (InvokeRequired)
                {
                    Invoke((Action) (() => textBox5.AppendText(content)));
                }
                else
                {
                    textBox5.AppendText(content);
                }
                _logBuilder.Append(content);
            }
        }
        private  void LogWritting()
        {
            (new Thread(() =>
            {
                using (var fs = new FileStream(LogPath, FileMode.Append, FileAccess.Write))
                {
                    using (var sw = new StreamWriter(fs) { AutoFlush = true })
                    {
                        while (true)
                        {
                            if (_logBuilder.Length > 0)
                            {
                                lock (_logBuilder)
                                {
                                    if (_logBuilder.Length > 0)
                                    {
                                        sw.Write(_logBuilder.ToString());
                                        _logBuilder.Clear();
                                    }
                                }

                            }
                            Thread.Sleep(500);
                        }
                    }

                }

            })
            { IsBackground = true }).Start();
        }

        private void TestListner(object obj)
        {
            var listner=new TcpListener(IPAddress.Parse(proxyIP),proxyPort);
            listner.Start();
            while (true)
            {
                var client = listner.AcceptTcpClient();
                var ns = client.GetStream();
                var bst = new byte[10240];
                var lo=new List<byte>();
                while (true)
                {
                    var len = ns.Read(bst, 0, bst.Length);
                    
                    //lo.AddRange(bst.Take(len));
                    if (len == 0)
                    {
                        ns.Write(lo.ToArray(), 0, lo.Count);
                        client.Close();
                        break;
                    }
                    ns.Write(bst, 0, len);
                }
            }
        }
       
    }
}
